<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <title>文件批量处理工具</title>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/xlsx/0.18.5/xlsx.full.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jszip/3.10.1/jszip.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/mammoth/1.6.0/mammoth.browser.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/docxtemplater/3.37.11/docxtemplater.js"></script>
    <script src="https://unpkg.com/pizzip@3.1.4/dist/pizzip.js"></script>
    <script src="https://unpkg.com/pizzip@3.1.4/dist/pizzip-utils.js"></script>
    <script>
        if (typeof XLSX === 'undefined') {
            document.write('<script src="https://unpkg.com/xlsx/dist/xlsx.full.min.js"><\/script>');
        }
        if (typeof JSZip === 'undefined') {
            document.write('<script src="https://unpkg.com/jszip/dist/jszip.min.js"><\/script>');
        }
    </script>
    <style>
        :root {
            --primary-color: #4361ee;
            --secondary-color: #3f37c9;
            --success-color: #4cc9f0;
            --warning-color: #f72585;
            --error-color: #e63946;
            --bg-color: #f8f9fa;
            --text-color: #2b2d42;
            --border-color: #e9ecef;
        }

        body {
            font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
            line-height: 1.6;
            color: var(--text-color);
            background-color: #f0f2f5;
            margin: 0;
            padding: 20px;
        }

        .container {
            max-width: 1000px;
            margin: 20px auto;
            background: white;
            padding: 30px;
            border-radius: 12px;
            box-shadow: 0 2px 15px rgba(0, 0, 0, 0.05);
        }

        h2 {
            color: var(--primary-color);
            font-size: 24px;
            margin-bottom: 25px;
            padding-bottom: 10px;
            border-bottom: 2px solid var(--border-color);
        }

        /* 功能选择区域样式 */
        .radio-group {
            display: flex;
            flex-wrap: wrap;
            gap: 12px;
            background: var(--bg-color);
            padding: 15px;
            border-radius: 8px;
            margin-bottom: 25px;
        }

        .radio-group label {
            flex: 1;
            min-width: 150px;
            display: flex;
            align-items: center;
            padding: 12px 20px;
            background: white;
            border: 1px solid var(--border-color);
            border-radius: 6px;
            cursor: pointer;
            transition: all 0.3s ease;
        }

        .radio-group label:hover {
            border-color: var(--primary-color);
            background: rgba(67, 97, 238, 0.05);
        }

        .radio-group input[type="radio"] {
            margin-right: 10px;
        }

        .radio-group input[type="radio"]:checked + label {
            background: var(--primary-color);
            color: white;
            border-color: var(--primary-color);
        }

        .file-type-group {
            margin-bottom: 15px;
        }

        /* 文件上传区域样式优化 */
        .file-control-wrapper {
            display: flex;
            align-items: center;
            gap: 10px;
            margin-bottom: 15px;
        }

        .file-input-group {
            flex: 1;
            position: relative;
            background: var(--bg-color);
            border: 1px dashed var(--border-color);
            border-radius: 6px;
            padding: 10px 15px;
            min-height: 42px;
            display: flex;
            align-items: center;
            justify-content: center;
            transition: all 0.3s ease;
        }

        .file-input-group:hover {
            border-color: var(--primary-color);
            background: rgba(67, 97, 238, 0.05);
        }

        .file-input-group input[type="file"] {
            position: absolute;
            width: 100%;
            height: 100%;
            top: 0;
            left: 0;
            opacity: 0;
            cursor: pointer;
            z-index: 2;
        }

        .file-input-text {
            display: flex;
            align-items: center;
            gap: 8px;
            color: var(--text-color);
            font-size: 14px;
        }

        .file-input-text i {
            font-size: 20px;
            color: var(--primary-color);
        }

        /* 清空按钮样式优化 */
        .btn-clear {
            padding: 8px 12px;
            background: white;
            border: 1px solid var(--error-color);
            color: var(--error-color);
            border-radius: 4px;
            font-size: 13px;
            display: inline-flex;
            align-items: center;
            gap: 4px;
            transition: all 0.2s ease;
            white-space: nowrap;
            height: 42px;
        }

        .btn-clear:hover {
            background: var(--error-color);
            color: white;
        }

        .btn-clear i {
            font-size: 14px;
        }

        /* 文件列表样式优化 */
        .file-list {
            margin-top: 10px;
            background: var(--bg-color);
            border-radius: 6px;
            padding: 5px;
        }

        .file-list-item {
            display: flex;
            justify-content: space-between;
            align-items: center;
            padding: 8px 12px;
            background: white;
            margin: 5px;
            border-radius: 4px;
            font-size: 13px;
        }

        .file-name {
            font-weight: 500;
            color: var(--text-color);
            max-width: 70%;
            overflow: hidden;
            text-overflow: ellipsis;
            white-space: nowrap;
        }

        .file-size {
            color: #6c757d;
            font-size: 12px;
        }

        /* 状态提示样式 */
        #status {
            margin-top: 20px;
            padding: 15px;
            border-radius: 8px;
            font-weight: 500;
        }

        #status.success {
            background: rgba(76, 201, 240, 0.1);
            color: var(--success-color);
            border-left: 4px solid var(--success-color);
        }

        #status.error {
            background: rgba(230, 57, 70, 0.1);
            color: var(--error-color);
            border-left: 4px solid var(--error-color);
        }

        /* 响应式设计 */
        @media (max-width: 768px) {
            .container {
                padding: 15px;
            }

            .radio-group label {
                min-width: 100%;
            }

            .file-control-wrapper {
                flex-direction: row; /* 保持在一行 */
            }
            
            .file-input-text span {
                display: none; /* 在移动端隐藏文字，只显示图标 */
            }
            
            .btn-clear {
                padding: 8px;
            }
            
            .btn-clear span {
                display: none; /* 在移动端隐藏文字，只显示图标 */
            }
        }

        /* 匹配模式和替换模式的样式 */
        .match-replace-group {
            display: flex;
            gap: 20px;
            margin-bottom: 20px;
        }

        .radio-options {
            display: flex;
            align-items: center;
            gap: 10px;
            background: var(--bg-color);
            padding: 10px 15px;
            border-radius: 6px;
        }

        .radio-options label {
            display: flex;
            align-items: center;
            gap: 5px;
            cursor: pointer;
            padding: 6px 12px;
            border-radius: 4px;
            transition: all 0.3s ease;
        }

        .radio-options label:hover {
            background: rgba(67, 97, 238, 0.05);
        }

        .radio-options input[type="radio"] {
            margin: 0;
        }

        .radio-options input[type="radio"]:checked + span {
            color: var(--primary-color);
            font-weight: 500;
        }

        /* 开始替换按钮样式 */
        .btn-start {
            background: var(--primary-color);
            color: white;
            padding: 10px 24px;
            border: none;
            border-radius: 6px;
            cursor: pointer;
            font-size: 14px;
            font-weight: 500;
            transition: all 0.3s ease;
        }

        .btn-start:hover {
            background: var(--secondary-color);
            transform: translateY(-1px);
            box-shadow: 0 2px 8px rgba(67, 97, 238, 0.2);
        }

        .btn-start:active {
            transform: translateY(0);
        }

        /* 查找和替换文本输入框样式优化 */
        .search-replace-container {
            display: flex;
            gap: 15px;
            margin-bottom: 20px;
        }

        .input-group {
            flex: 1;
            position: relative;
        }

        .input-group label {
            display: block;
            font-size: 13px;
            color: var(--text-color);
            margin-bottom: 6px;
            font-weight: 500;
        }

        .input-group input[type="text"] {
            width: 100%;
            padding: 8px 12px;
            border: 1px solid var(--border-color);
            border-radius: 6px;
            font-size: 14px;
            color: var(--text-color);
            background: white;
            transition: all 0.3s ease;
        }

        .input-group input[type="text"]:hover {
            border-color: var(--primary-color);
        }

        .input-group input[type="text"]:focus {
            outline: none;
            border-color: var(--primary-color);
            box-shadow: 0 0 0 3px rgba(67, 97, 238, 0.1);
        }

        .input-group input[type="text"]::placeholder {
            color: #adb5bd;
        }

        /* 添加图标 */
        .input-group::before {
            content: '🔍';
            position: absolute;
            left: 10px;
            top: 33px;
            font-size: 14px;
            color: var(--text-color);
            opacity: 0.5;
        }

        .input-group.replace::before {
            content: '✏️';
        }

        .input-group input[type="text"] {
            padding-left: 32px;
        }
    </style>
</head>
<body>
    <div class="container">
        <h2>文件批量处理工具</h2>
        
        <div class="radio-group">
            <label>功能选择：</label>
            <label>
                <input type="radio" name="functionType" value="excel" checked>
                Excel内容替换
            </label>
            <label>
                <input type="radio" name="functionType" value="word">
                Word内容替换
            </label>
            <label>
                <input type="radio" name="functionType" value="rename">
                文件批量重命名
            </label>
        </div>

        <div id="excelSection">
            <div class="file-type-group">
                <label>
                    <input type="radio" name="excelFileType" value="excel" checked> Excel文件
                </label>
                <label>
                    <input type="radio" name="excelFileType" value="zip"> ZIP压缩文件
                </label>
            </div>

            <div class="file-control-wrapper">
                <div class="file-input-group">
                    <input type="file" id="files" multiple>
                    <div class="file-input-text">
                        <i>📁</i>
                        <span>选择或拖放文件</span>
                    </div>
                </div>
                <button class="btn-clear" onclick="clearFiles()">
                    <i>❌</i>
                    <span>清空</span>
                </button>
            </div>

            <div class="search-replace-container">
                <div class="input-group">
                    <label for="searchText">查找文本：</label>
                    <input type="text" 
                           id="searchText" 
                           placeholder="请输入要查找的文本"
                           value="111">
                </div>

                <div class="input-group replace">
                    <label for="replaceText">替换为：</label>
                    <input type="text" 
                           id="replaceText" 
                           placeholder="请输入替换后的文本"
                           value="哈哈哈">
                </div>
            </div>

            <div class="match-replace-group">
                <div class="radio-options">
                    <span>匹配模式：</span>
                    <label>
                        <input type="radio" name="matchMode" value="partial" checked>
                        <span>模糊匹配</span>
                    </label>
                    <label>
                        <input type="radio" name="matchMode" value="exact">
                        <span>精确匹配</span>
                    </label>
                </div>

                <div class="radio-options">
                    <span>替换模式：</span>
                    <label>
                        <input type="radio" name="replaceMode" value="all" checked>
                        <span>全部替换</span>
                    </label>
                    <label>
                        <input type="radio" name="replaceMode" value="first">
                        <span>仅替换首个</span>
                    </label>
                </div>
            </div>

            <button class="btn-start" onclick="processFiles()">开始替换</button>
        </div>

        <div id="wordSection" style="display: none;">
            <div class="file-type-group">
                <label>
                    <input type="radio" name="wordFileType" value="word" checked> Word文件
                </label>
                <label>
                    <input type="radio" name="wordFileType" value="zip"> ZIP压缩文件
                </label>
            </div>

            <div class="file-control-wrapper">
                <div class="file-input-group">
                    <input type="file" id="wordFiles" accept=".docx" multiple>
                    <div class="file-input-text">
                        <i>📁</i>
                        <span>选择文件或拖放文件到此处</span>
                    </div>
                </div>
                <button class="btn-clear" onclick="clearWordFiles()">
                    <i>❌</i> 清空选择
                </button>
            </div>

            <div class="search-replace-container">
                <div class="input-group">
                    <label for="wordSearchText">查找文本：</label>
                    <input type="text" 
                           id="wordSearchText" 
                           placeholder="请输入要查找的文本">
                </div>

                <div class="input-group replace">
                    <label for="wordReplaceText">替换为：</label>
                    <input type="text" 
                           id="wordReplaceText" 
                           placeholder="请输入替换后的文本">
                </div>
            </div>

            <div class="radio-group">
                <label>匹配模式：</label>
                <label>
                    <input type="radio" name="wordMatchMode" value="partial" checked>
                    模糊匹配
                </label>
                <label>
                    <input type="radio" name="wordMatchMode" value="exact">
                    精确匹配
                </label>
            </div>

            <div class="radio-group">
                <label>替换模式：</label>
                <label>
                    <input type="radio" name="wordReplaceMode" value="all" checked>
                    全部替换
                </label>
                <label>
                    <input type="radio" name="wordReplaceMode" value="first">
                    仅替换首个
                </label>
            </div>

            <button onclick="processWordFiles()">开始替换</button>
        </div>

        <div id="renameSection" style="display: none;">
            <div class="file-type-group">
                <label>
                    <input type="radio" name="renameFileType" value="normal" checked> 普通文件
                </label>
                <label>
                    <input type="radio" name="renameFileType" value="zip"> ZIP压缩文件
                </label>
            </div>

            <div class="file-control-wrapper">
                <div class="file-input-group">
                    <input type="file" id="renameFiles" multiple>
                    <div class="file-input-text">
                        <i>📁</i>
                        <span>选择文件或拖放文件到此处</span>
                    </div>
                </div>
                <button class="btn-clear" onclick="clearRenameFiles()">
                    <i>❌</i> 清空选择
                </button>
            </div>

            <div class="radio-group">
                <label>重命名规则：</label>
                <label>
                    <input type="radio" name="renameRule" value="custom" checked>
                    自定义替换
                </label>
                <label>
                    <input type="radio" name="renameRule" value="prefix">
                    添加前缀
                </label>
                <label>
                    <input type="radio" name="renameRule" value="suffix">
                    添加后缀
                </label>
                <label>
                    <input type="radio" name="renameRule" value="sequence">
                    添加序号
                </label>
                <label>
                    <input type="radio" name="renameRule" value="regex">
                    正则提取
                </label>
            </div>

            <div id="customRename">
                <div class="input-group">
                    <label for="searchPattern">查找文本：</label>
                    <input type="text" id="searchPattern">
                </div>

                <div class="input-group">
                    <label for="replacePattern">替换为：</label>
                    <input type="text" id="replacePattern">
                </div>

                <div class="radio-group">
                    <label>匹配模式：</label>
                    <label>
                        <input type="radio" name="renameMatchMode" value="partial" checked>
                        模糊匹配
                    </label>
                    <label>
                        <input type="radio" name="renameMatchMode" value="exact">
                        精确匹配
                    </label>
                </div>
            </div>

            <div id="affixRename" style="display: none;">
                <div class="input-group">
                    <label for="affixText">输入文本：</label>
                    <input type="text" id="affixText">
                </div>
            </div>

            <div id="sequenceRename" style="display: none;">
                <div class="input-group">
                    <label for="sequenceStart">起始序号：</label>
                    <input type="number" id="sequenceStart" value="1" min="0">
                </div>
                <div class="input-group">
                    <label for="sequenceDigits">序号位数：</label>
                    <input type="number" id="sequenceDigits" value="3" min="1" max="10">
                </div>
                <div class="input-group">
                    <label for="sequencePrefix">序号前缀文本（可选）：</label>
                    <input type="text" id="sequencePrefix" placeholder="例如: IMG_">
                </div>
            </div>

            <div id="regexRename" style="display: none;">
                <div class="input-group">
                    <label for="regexPattern">正则表达式：</label>
                    <input type="text" id="regexPattern" placeholder="例如: .*?(\d+).*">
                    <div class="help-text">使用()括号来标记要提取的部分</div>
                </div>
                <div class="input-group">
                    <label for="regexTemplate">输出模板：</label>
                    <input type="text" id="regexTemplate" placeholder="例如: file_$1">
                    <div class="help-text">使用$1,$2等来引用提取的内容</div>
                </div>
                <div class="input-group">
                    <label for="regexExample">示例：</label>
                    <select id="regexExample" onchange="loadRegexExample()">
                        <option value="">选择预设模板...</option>
                        <option value="number">提取数字</option>
                        <option value="date">提取日期</option>
                        <option value="custom">自定义模式</option>
                    </select>
                </div>
            </div>

            <button onclick="processRename()">开始重命名</button>
        </div>

        <div id="status"></div>
    </div>

    <div id="fileList" class="file-list" style="display: none;">
        <!-- 文件列表将通过JavaScript动态添加 -->
    </div>

    <script>
        window.onload = function() {
            if (typeof XLSX === 'undefined') {
                document.getElementById('status').innerHTML = '错误：Excel处理库加载失败，请检查网络连接';
                document.getElementById('status').className = 'error';
                return;
            }
        };

        document.querySelectorAll('input[name="fileType"]').forEach(radio => {
            radio.addEventListener('change', function() {
                const fileInput = document.getElementById('files');
                fileInput.accept = this.value === 'zip' ? '.zip' : '.xlsx,.xls';
            });
        });

        function showFileInfo(input) {
            const fileList = document.getElementById('fileList');
            if (input.files.length > 0) {
                let fileListHTML = '';
                Array.from(input.files).forEach(file => {
                    fileListHTML += `
                        <div class="file-list-item">
                            <span class="file-name">${file.name}</span>
                            <span class="file-size">${formatFileSize(file.size)}</span>
                        </div>
                    `;
                });
                fileList.innerHTML = fileListHTML;
                fileList.style.display = 'block';
            } else {
                fileList.style.display = 'none';
            }
        }

        function formatFileSize(bytes) {
            if (bytes === 0) return '0 Bytes';
            const k = 1024;
            const sizes = ['Bytes', 'KB', 'MB', 'GB'];
            const i = Math.floor(Math.log(bytes) / Math.log(k));
            return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
        }

        function clearFiles() {
            const fileInput = document.getElementById('files');
            fileInput.value = '';
            document.getElementById('fileList').style.display = 'none';
        }

        async function processFiles() {
            const files = document.getElementById('files').files;
            const searchText = document.getElementById('searchText').value;
            const replaceText = document.getElementById('replaceText').value;
            const exactMatch = document.querySelector('input[name="matchMode"]:checked').value === 'exact';
            const replaceAll = document.querySelector('input[name="replaceMode"]:checked').value === 'all';
            const status = document.getElementById('status');
            const isZipMode = document.querySelector('input[name="fileType"]:checked').value === 'zip';

            if (files.length === 0) {
                status.innerHTML = '请选择文件';
                status.className = 'error';
                return;
            }

            status.innerHTML = '处理中...';
            status.className = '';

            if (isZipMode) {
                await processZipFiles(files, searchText, replaceText, exactMatch, replaceAll, status);
            } else {
                await processExcelFiles(files, searchText, replaceText, exactMatch, replaceAll, status);
            }
        }

        async function processZipFiles(files, searchText, replaceText, exactMatch, replaceAll, status) {
            const zip = new JSZip();
            const outputZip = new JSZip();

            for (let file of files) {
                try {
                    if (!file.name.endsWith('.zip')) {
                        throw new Error('请选择ZIP文件');
                    }

                    const zipContent = await JSZip.loadAsync(file);
                    let processedFiles = 0;

                    for (let [filename, zipEntry] of Object.entries(zipContent.files)) {
                        if (!zipEntry.dir && /\.(xlsx|xls)$/i.test(filename)) {
                            const content = await zipEntry.async('arraybuffer');
                            const workbook = XLSX.read(content);
                            let replacementCount = 0;

                            workbook.SheetNames.forEach(sheetName => {
                                const worksheet = workbook.Sheets[sheetName];
                                
                                for (let cell in worksheet) {
                                    if (cell[0] === '!') continue;
                                    
                                    if (worksheet[cell].v !== undefined) {
                                        const cellValue = String(worksheet[cell].v);
                                        
                                        if (exactMatch) {
                                            if (cellValue === searchText) {
                                                worksheet[cell].v = replaceText;
                                                replacementCount++;
                                            }
                                        } else {
                                            if (cellValue.includes(searchText)) {
                                                if (replaceAll) {
                                                    worksheet[cell].v = cellValue.replace(new RegExp(searchText, 'g'), replaceText);
                                                } else {
                                                    worksheet[cell].v = cellValue.replace(searchText, replaceText);
                                                }
                                                replacementCount++;
                                            }
                                        }
                                    }
                                }
                            });

                            const excelBuffer = XLSX.write(workbook, { bookType: 'xlsx', type: 'array' });
                            outputZip.file(`modified_${filename}`, excelBuffer);
                            processedFiles++;
                            status.innerHTML += `<br>处理文件 ${filename}：替换了 ${replacementCount} 处内容`;
                        }
                    }

                    if (processedFiles === 0) {
                        throw new Error('ZIP文件中没有找到Excel文件');
                    }

                    const content = await outputZip.generateAsync({type: 'blob'});
                    const url = URL.createObjectURL(content);
                    const a = document.createElement('a');
                    a.href = url;
                    a.download = `modified_${file.name}`;
                    document.body.appendChild(a);
                    a.click();
                    document.body.removeChild(a);
                    URL.revokeObjectURL(url);

                    status.innerHTML += `<br>ZIP文件 ${file.name} 处理完成！`;
                } catch (error) {
                    status.innerHTML += `<br>处理ZIP文件 ${file.name} 时出错: ${error.message}`;
                    status.className = 'error';
                    continue;
                }
            }

            status.innerHTML += '<br>所有ZIP文件处理完成！';
            status.className = 'success';
        }

        async function processExcelFiles(files, searchText, replaceText, exactMatch, replaceAll, status) {
            for (let file of files) {
                try {
                    if (!file.name.match(/\.(xlsx|xls)$/i)) {
                        throw new Error('不支持的文件格式，请选择.xlsx或.xls文件');
                    }

                    const data = await file.arrayBuffer();
                    const workbook = XLSX.read(data);
                    let replacementCount = 0;

                    workbook.SheetNames.forEach(sheetName => {
                        const worksheet = workbook.Sheets[sheetName];
                        
                        for (let cell in worksheet) {
                            if (cell[0] === '!') continue;
                            
                            if (worksheet[cell].v !== undefined) {
                                const cellValue = String(worksheet[cell].v);
                                
                                if (exactMatch) {
                                    if (cellValue === searchText) {
                                        worksheet[cell].v = replaceText;
                                        replacementCount++;
                                    }
                                } else {
                                    if (cellValue.includes(searchText)) {
                                        if (replaceAll) {
                                            worksheet[cell].v = cellValue.replace(new RegExp(searchText, 'g'), replaceText);
                                        } else {
                                            worksheet[cell].v = cellValue.replace(searchText, replaceText);
                                        }
                                        replacementCount++;
                                    }
                                }
                            }
                        }
                    });

                    const newFile = XLSX.write(workbook, { bookType: 'xlsx', type: 'array' });
                    
                    const blob = new Blob([newFile], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
                    const url = URL.createObjectURL(blob);
                    const a = document.createElement('a');
                    a.href = url;
                    a.download = 'modified_' + file.name;
                    document.body.appendChild(a);
                    a.click();
                    document.body.removeChild(a);
                    URL.revokeObjectURL(url);
                    
                    status.innerHTML += `<br>文件 ${file.name} 处理成功！共替换了 ${replacementCount} 处内容。`;
                } catch (error) {
                    status.innerHTML += `<br>处理文件 ${file.name} 时出错: ${error.message}`;
                    status.className = 'error';
                    continue;
                }
            }

            status.innerHTML += '<br>所有文件处理完成！';
            status.className = 'success';
        }

        document.getElementById('files').addEventListener('change', function(e) {
            const status = document.getElementById('status');
            if (this.files.length > 0) {
                status.innerHTML = `已选择 ${this.files.length} 个文件`;
                status.className = '';
            } else {
                status.innerHTML = '请选择文件';
                status.className = 'error';
            }
        });

        document.querySelectorAll('input[name="functionType"]').forEach(radio => {
            radio.addEventListener('change', function() {
                document.getElementById('excelSection').style.display = 
                    this.value === 'excel' ? 'block' : 'none';
                document.getElementById('wordSection').style.display = 
                    this.value === 'word' ? 'block' : 'none';
                document.getElementById('renameSection').style.display = 
                    this.value === 'rename' ? 'block' : 'none';
            });
        });

        function clearRenameFiles() {
            const fileInput = document.getElementById('renameFiles');
            fileInput.value = '';
            document.getElementById('status').innerHTML = '已清空文件选择';
            document.getElementById('status').className = '';
        }

        document.querySelectorAll('input[name="renameRule"]').forEach(radio => {
            radio.addEventListener('change', function() {
                document.getElementById('customRename').style.display = 
                    this.value === 'custom' ? 'block' : 'none';
                document.getElementById('affixRename').style.display = 
                    (this.value === 'prefix' || this.value === 'suffix') ? 'block' : 'none';
                document.getElementById('sequenceRename').style.display = 
                    this.value === 'sequence' ? 'block' : 'none';
                document.getElementById('regexRename').style.display = 
                    this.value === 'regex' ? 'block' : 'none';
            });
        });

        document.querySelectorAll('input[name="renameFileType"]').forEach(radio => {
            radio.addEventListener('change', function() {
                const fileInput = document.getElementById('renameFiles');
                if (this.value === 'zip') {
                    fileInput.accept = '.zip';
                    fileInput.multiple = false;
                } else {
                    fileInput.accept = '';
                    fileInput.multiple = true;
                }
            });
        });

        async function processRename() {
            const files = document.getElementById('renameFiles').files;
            const renameRule = document.querySelector('input[name="renameRule"]:checked').value;
            const isZipMode = document.querySelector('input[name="renameFileType"]:checked').value === 'zip';
            const status = document.getElementById('status');

            if (files.length === 0) {
                status.innerHTML = '请选择文件';
                status.className = 'error';
                return;
            }

            status.innerHTML = '处理中...';
            status.className = '';

            try {
                if (isZipMode) {
                    await processZipRename(files[0], renameRule, status);
                } else {
                    await processNormalRename(files, renameRule, status);
                }
            } catch (error) {
                status.innerHTML = `处理出错: ${error.message}`;
                status.className = 'error';
            }
        }

        async function processZipRename(zipFile, renameRule, status) {
            if (!zipFile.name.endsWith('.zip')) {
                throw new Error('请选择ZIP文件');
            }

            const zip = new JSZip();
            const outputZip = new JSZip();
            const zipContent = await JSZip.loadAsync(zipFile);
            let processedCount = 0;

            for (let [filename, zipEntry] of Object.entries(zipContent.files)) {
                if (!zipEntry.dir) {
                    const fileContent = await zipEntry.async('arraybuffer');
                    let newFileName = '';

                    switch (renameRule) {
                        case 'custom':
                            const searchPattern = document.getElementById('searchPattern').value;
                            const replacePattern = document.getElementById('replacePattern').value;
                            const exactMatch = document.querySelector('input[name="renameMatchMode"]:checked').value === 'exact';
                            
                            if (exactMatch) {
                                newFileName = filename.replace(searchPattern, replacePattern);
                            } else {
                                newFileName = filename.replace(new RegExp(searchPattern, 'g'), replacePattern);
                            }
                            break;

                        case 'prefix':
                            const prefix = document.getElementById('affixText').value;
                            newFileName = prefix + filename;
                            break;

                        case 'suffix':
                            const suffix = document.getElementById('affixText').value;
                            const lastSlashIndex = filename.lastIndexOf('/');
                            const pathPart = lastSlashIndex !== -1 ? filename.substring(0, lastSlashIndex + 1) : '';
                            const filePart = lastSlashIndex !== -1 ? filename.substring(lastSlashIndex + 1) : filename;
                            const dotIndex = filePart.lastIndexOf('.');
                            if (dotIndex === -1) {
                                newFileName = pathPart + filePart + suffix;
                            } else {
                                newFileName = pathPart + filePart.substring(0, dotIndex) + suffix + filePart.substring(dotIndex);
                            }
                            break;

                        case 'sequence':
                            const startNum = parseInt(document.getElementById('sequenceStart').value);
                            const digits = parseInt(document.getElementById('sequenceDigits').value);
                            const seqPrefix = document.getElementById('sequencePrefix').value;
                            const extension = filename.split('.').pop();
                            const sequence = String(startNum + processedCount).padStart(digits, '0');
                            newFileName = `${seqPrefix}${sequence}.${extension}`;
                            break;

                        case 'regex':
                            newFileName = processRegexRename(filename);
                            break;
                    }

                    outputZip.file(newFileName, fileContent);
                    processedCount++;
                    status.innerHTML += `<br>处理文件: ${filename} -> ${newFileName}`;
                }
            }

            if (processedCount === 0) {
                throw new Error('ZIP文件中没有找到文件');
            }

            const content = await outputZip.generateAsync({type: 'blob'});
            const url = URL.createObjectURL(content);
            const a = document.createElement('a');
            a.href = url;
            a.download = `renamed_${zipFile.name}`;
            document.body.appendChild(a);
            a.click();
            document.body.removeChild(a);
            URL.revokeObjectURL(url);

            status.innerHTML += `<br>ZIP文件处理完成！共处理 ${processedCount} 个文件`;
            status.className = 'success';
        }

        async function processNormalRename(files, renameRule, status) {
            const zip = new JSZip();
            let processedCount = 0;

            for (let i = 0; i < files.length; i++) {
                const file = files[i];
                const fileContent = await file.arrayBuffer();
                let newFileName = '';

                switch (renameRule) {
                    case 'custom':
                        const searchPattern = document.getElementById('searchPattern').value;
                        const replacePattern = document.getElementById('replacePattern').value;
                        const exactMatch = document.querySelector('input[name="renameMatchMode"]:checked').value === 'exact';
                        
                        if (exactMatch) {
                            newFileName = file.name.replace(searchPattern, replacePattern);
                        } else {
                            newFileName = file.name.replace(new RegExp(searchPattern, 'g'), replacePattern);
                        }
                        break;

                    case 'prefix':
                        const prefix = document.getElementById('affixText').value;
                        newFileName = prefix + file.name;
                        break;

                    case 'suffix':
                        const suffix = document.getElementById('affixText').value;
                        const dotIndex = file.name.lastIndexOf('.');
                        if (dotIndex === -1) {
                            newFileName = file.name + suffix;
                        } else {
                            newFileName = file.name.substring(0, dotIndex) + suffix + file.name.substring(dotIndex);
                        }
                        break;

                    case 'sequence':
                        const startNum = parseInt(document.getElementById('sequenceStart').value);
                        const digits = parseInt(document.getElementById('sequenceDigits').value);
                        const seqPrefix = document.getElementById('sequencePrefix').value;
                        const extension = file.name.split('.').pop();
                        const sequence = String(startNum + i).padStart(digits, '0');
                        newFileName = `${seqPrefix}${sequence}.${extension}`;
                        break;

                    case 'regex':
                        newFileName = processRegexRename(file.name);
                        break;
                }

                zip.file(newFileName, fileContent);
                processedCount++;
                status.innerHTML += `<br>处理文件: ${file.name} -> ${newFileName}`;
            }

            const content = await zip.generateAsync({type: 'blob'});
            const url = URL.createObjectURL(content);
            const a = document.createElement('a');
            a.href = url;
            a.download = 'renamed_files.zip';
            document.body.appendChild(a);
            a.click();
            document.body.removeChild(a);
            URL.revokeObjectURL(url);

            status.innerHTML += `<br>所有文件处理完成！共处理 ${processedCount} 个文件`;
            status.className = 'success';
        }

        function loadRegexExample() {
            const example = document.getElementById('regexExample').value;
            const patternInput = document.getElementById('regexPattern');
            const templateInput = document.getElementById('regexTemplate');
            
            switch(example) {
                case 'number':
                    patternInput.value = '.*?([0-9]+).*';
                    templateInput.value = 'file_$1';
                    break;
                case 'date':
                    patternInput.value = '.*?([0-9]{4})[-_]?([0-9]{2})[-_]?([0-9]{2}).*';
                    templateInput.value = '$1年$2月$3日_文件';
                    break;
                case 'custom':
                    patternInput.value = '';
                    templateInput.value = '';
                    break;
            }
        }

        function processRegexRename(fileName) {
            const pattern = document.getElementById('regexPattern').value;
            const template = document.getElementById('regexTemplate').value;
            
            try {
                const regex = new RegExp(pattern);
                const matches = fileName.match(regex);
                
                if (!matches) {
                    return fileName; // 如果没有匹配，返回原文件名
                }
                
                let newName = template;
                for (let i = 1; i < matches.length; i++) {
                    newName = newName.replace(`$${i}`, matches[i] || '');
                }
                
                // 保持原有的文件扩展名
                const extension = fileName.split('.').pop();
                if (!newName.endsWith('.' + extension)) {
                    newName += '.' + extension;
                }
                
                return newName;
            } catch (error) {
                console.error('正则表达式错误:', error);
                return fileName;
            }
        }

        document.querySelectorAll('input[name="wordFileType"]').forEach(radio => {
            radio.addEventListener('change', function() {
                const fileInput = document.getElementById('wordFiles');
                fileInput.accept = this.value === 'zip' ? '.zip' : '.docx';
                fileInput.multiple = this.value !== 'zip';
            });
        });

        function clearWordFiles() {
            const fileInput = document.getElementById('wordFiles');
            fileInput.value = '';
            document.getElementById('status').innerHTML = '已清空文件选择';
            document.getElementById('status').className = '';
        }

        async function processWordFiles() {
            const files = document.getElementById('wordFiles').files;
            const searchText = document.getElementById('wordSearchText').value;
            const replaceText = document.getElementById('wordReplaceText').value;
            const exactMatch = document.querySelector('input[name="wordMatchMode"]:checked').value === 'exact';
            const replaceAll = document.querySelector('input[name="wordReplaceMode"]:checked').value === 'all';
            const isZipMode = document.querySelector('input[name="wordFileType"]:checked').value === 'zip';
            const status = document.getElementById('status');

            if (files.length === 0) {
                status.innerHTML = '请选择文件';
                status.className = 'error';
                return;
            }

            status.innerHTML = '处理中...';
            status.className = '';

            try {
                if (isZipMode) {
                    await processZipWordFiles(files[0], searchText, replaceText, exactMatch, replaceAll, status);
                } else {
                    await processNormalWordFiles(files, searchText, replaceText, exactMatch, replaceAll, status);
                }
            } catch (error) {
                status.innerHTML = `处理出错: ${error.message}`;
                status.className = 'error';
            }
        }

        async function processNormalWordFiles(files, searchText, replaceText, exactMatch, replaceAll, status) {
            const zip = new JSZip();
            let processedCount = 0;

            for (let file of files) {
                try {
                    const arrayBuffer = await file.arrayBuffer();
                    // 直接处理Word文档
                    const newContent = await replaceDocxContent(arrayBuffer, {
                        searchText,
                        replaceText,
                        exactMatch,
                        replaceAll
                    });
                    
                    zip.file(`modified_${file.name}`, newContent);
                    processedCount++;
                    status.innerHTML += `<br>处理文件: ${file.name}`;
                } catch (error) {
                    status.innerHTML += `<br>处理文件 ${file.name} 时出错: ${error.message}`;
                    continue;
                }
            }

            const content = await zip.generateAsync({type: 'blob'});
            const url = URL.createObjectURL(content);
            const a = document.createElement('a');
            a.href = url;
            a.download = 'modified_word_files.zip';
            document.body.appendChild(a);
            a.click();
            document.body.removeChild(a);
            URL.revokeObjectURL(url);

            status.innerHTML += `<br>所有文件处理完成！共处理 ${processedCount} 个文件`;
            status.className = 'success';
        }

        async function processZipWordFiles(zipFile, searchText, replaceText, exactMatch, replaceAll, status) {
            if (!zipFile.name.endsWith('.zip')) {
                throw new Error('请选择ZIP文件');
            }

            const zip = new JSZip();
            const outputZip = new JSZip();
            const zipContent = await JSZip.loadAsync(zipFile);
            let processedCount = 0;

            for (let [filename, zipEntry] of Object.entries(zipContent.files)) {
                if (!zipEntry.dir && filename.endsWith('.docx')) {
                    try {
                        const arrayBuffer = await zipEntry.async('arraybuffer');
                        // 直接处理Word文档
                        const newContent = await replaceDocxContent(arrayBuffer, {
                            searchText,
                            replaceText,
                            exactMatch,
                            replaceAll
                        });

                        outputZip.file(`modified_${filename}`, newContent);
                        processedCount++;
                        status.innerHTML += `<br>处理文件: ${filename}`;
                    } catch (error) {
                        status.innerHTML += `<br>处理文件 ${filename} 时出错: ${error.message}`;
                        continue;
                    }
                }
            }

            if (processedCount === 0) {
                throw new Error('ZIP文件中没有找到Word文档');
            }

            const content = await outputZip.generateAsync({type: 'blob'});
            const url = URL.createObjectURL(content);
            const a = document.createElement('a');
            a.href = url;
            a.download = `modified_${zipFile.name}`;
            document.body.appendChild(a);
            a.click();
            document.body.removeChild(a);
            URL.revokeObjectURL(url);

            status.innerHTML += `<br>ZIP文件处理完成！共处理 ${processedCount} 个文件`;
            status.className = 'success';
        }

        async function replaceDocxContent(docxArrayBuffer, options) {
            try {
                // 创建PizZip实例
                const zip = new PizZip(docxArrayBuffer);
                
                // 读取document.xml
                const documentXml = zip.files['word/document.xml'].asText();
                
                // 从options中获取参数
                const { searchText, replaceText, exactMatch, replaceAll } = options;
                
                // 替换文本内容
                const updatedXml = documentXml.replace(/(<w:t[^>]*>)(.*?)(<\/w:t>)/g, function(match, startTag, content, endTag) {
                    // 对每个文本节点进行替换
                    if (content.includes(searchText)) {
                        if (exactMatch) {
                            if (replaceAll) {
                                content = content.split(searchText).join(replaceText);
                            } else {
                                content = content.replace(searchText, replaceText);
                            }
                        } else {
                            const regex = new RegExp(searchText, replaceAll ? 'g' : '');
                            content = content.replace(regex, replaceText);
                        }
                    }
                    return startTag + content + endTag;
                });
                
                // 更新document.xml
                zip.file('word/document.xml', updatedXml);
                
                // 生成新的docx文件
                const newDocxContent = zip.generate({
                    type: 'arraybuffer',
                    compression: 'DEFLATE',
                    compressionOptions: {
                        level: 9
                    }
                });
                
                return newDocxContent;
            } catch (error) {
                console.error('处理Word文档时出错:', error);
                throw error;
            }
        }
    </script>
</body>
</html> 
</html> 